# -*- coding: utf-8 -*-
""" A Coordinate Dialog Module.

The CoordDialog class handles a dialog for converting coordinate pairs or files
from one Datum / Projection to another interactively.

    :Author:
      - 20111227-20120111 Roberto Vidmar

    :Revision:  $Revision: 57 $
                $Date: 2012-11-23 14:34:10 +0000 (Fri, 23 Nov 2012) $

    :Copyright: 2011-2012
                Nicola Creati <ncreati@inogs.it>
                Roberto Vidmar <rvidmar@inogs.it>

    :License: MIT/X11 License (see :download:`license.txt
                               <../../license.txt>`)
"""

import sys
import codecs
import time
import numpy as np

from pyproj import Proj, transform
from qtCompat import Qt, QtCore, QtGui

QCA = QtCore.QCoreApplication
import icons_rc
from degrees import d2dm, d2dms
from coordWidget import CoordWidget
from filePicker import FilePicker
from fieldsWizard import FieldsWizard, readASCII
from progressDialog import ProgressDialog, ThreadedFunc

Revision = '$Revision: 57 $'

def unimplemented():
  """ Display an 'Unimplemented' message
  """
  mbox = QtGui.QMessageBox()
  mbox.setWindowTitle(QCA.translate("UnimplementedMessage", 'Unimplemented'))
  mbox.setIcon(QtGui.QMessageBox.Information)
  mbox.setInformativeText(QCA.translate("UnimplementedMessage",
    "This conversion has not been\n"
    "implemented yet."))
  mbox.setStandardButtons(QtGui.QMessageBox.Ok)
  mbox.setDefaultButton(QtGui.QMessageBox.Ok)
  mbox.button(QtGui.QMessageBox.Ok).setText(
    QCA.translate("UnimplementedMessage", 'Ok'))
  mbox.exec_()

def noDatumShift((phi, lamda)):
  """ Display a 'noDatumShift' message
  """
  utfCodec = QtCore.QTextCodec.codecForName("UTF-8")
  QtCore.QTextCodec.setCodecForTr(utfCodec);
  mbox = QtGui.QMessageBox()
  mbox.setWindowTitle(QCA.translate("noDatumShift", 'No Datum Shift'))
  mbox.setIcon(QtGui.QMessageBox.Information)
  mbox.setInformativeText(QCA.translate("noDatumShift",
    "Datum shift matrix is undefined in\n"
    "φ = %.9f λ = %.9f." % (phi, lamda)))
  mbox.setStandardButtons(QtGui.QMessageBox.Ok)
  mbox.setDefaultButton(QtGui.QMessageBox.Ok)
  mbox.button(QtGui.QMessageBox.Ok).setText(
    QCA.translate("noDatumShift", 'Ok'))
  mbox.exec_()

def writeASCII(progress, quitFunc, pn, xyz, fmt, header='',
  recsPerChunk=1000000):
  """ Write xyz (n x npoints) to ASCII File pn in chunks with optional Header

    :param progress: progress function. This funtion is called at every step.
    :type progress: function
    :param quitFunc: quit function. This funtion is called at every step and if
                     it returns True it's time to quit.
    :type quitFunc: function
    :param pn: pathname of the file to write
    :type pn: string, unicode
    :param xyz: dataset to write
    :type xyz: numpy array 3xN
    :param fmt: format to use to output data to ASCII
    :type fmt: string
    :param header: optional header
    :type header: string
    :param recsPerChunk: number of records to write at every iteration (chunk)
    :type recsPerChunk: int
    :raises:
  """
  # Write coordinates to output
  #fid = codecs.open(pn, "w", 'UTF-8')
  fid = open(pn, "w")

  # Write an optional header
  if header:
    fid.write(header)

  recsWritten = 0
  recsToWrite = xyz.shape[1]
  remainingRecords = recsToWrite
  while remainingRecords:
    # Adjust recsPerChunk
    recsPerChunk = min(recsPerChunk, remainingRecords)
    start = recsToWrite - remainingRecords
    end = start + recsPerChunk

    # Black Magic...
    values = np.ravel(np.vstack((c[start: end] for c in xyz)).T)
    chunk = fmt * recsPerChunk % tuple(values)
    fid.write(chunk)

    # Save number of records actually read
    recsWritten += recsPerChunk
    remainingRecords -= recsPerChunk
    # Memory mapped array?
    #if hasattr(points, 'flush'):
    #  points.flush()
    if quitFunc():
      break
    pcent = 100. * recsWritten / recsToWrite
    progress(pcent)
  fid.close()

#===============================================================================
class CoordDialog(QtGui.QDialog):
  """ A coordinates dialog class to represent a 3D point in two different
      datums and projections.

      The dialog support also conversion of files.

    :Author: R. Vidmar, 20111227
  """
  ModePoint = 0
  ModeFile = 1

  def __init__(self, xyz, projFrom=CoordWidget.WGS84, projTo=CoordWidget.WGS84,
    ell2Ortho=None, name='', upperMode=CoordWidget.ModeD,
    lowerMode=CoordWidget.ModeDMS, dmsChars=[u"°", u"'", u'"'], parent=None):
    """ Create a new CoordDialog instance.

        :param xyz: Tuple (x, y, z) where: x = Easting or longitude,
                    y = Northing or latitude, z = Ellipsoidical height
        :type xyz: tuple
        :param projFrom: PROJ.4 string defining x, y, z
        :type projFrom: string
        :param projTo: PROJ.4 string defining the new datum/projection
        :type projTo: string
        :param ell2Ortho: offset to add to z to obtain orthometric height
        :type ell2Ortho: float
        :param name: optional name of this point
        :type name: string, unicode
        :param upperMode: mode at init: (0, ... CoordWidget.ModeFile) for the
                          upper coordWidget
        :type upperMode: int
        :param lowerMode: mode at init: (0, ... CoordWidget.ModeFile) for the
                          lower coordWidget
        :type lowerMode: int
        :param dmsChars: Separators for degrees, minutes, seconds
                         ([u"°", u"'", u'"'])
        :type dmsChars: tuple
        :param parent: parent widget
        :type parent: QtGui widget
    """
    super(CoordDialog, self).__init__(parent)

    self.setWindowTitle(QCA.translate("coordDialog",
      "Proj.4 Coordinate Converter - Rev. %s") % Revision.split()[1])
    if name:
      self.setObjectName(name)
      pointLabel = QtGui.QLabel(name)
      f = pointLabel.font()
      f.setBold(True)
      pointLabel.setFont(f)
      pointLabel.setToolTip(QCA.translate("coordDialog",
        "The name of this point"))
    else:
      pointLabel = None
    self.inC = self.outC = None
    self._lastInputFilePath = None
    self._dmsChars = dmsChars
    self._logo1 = QtGui.QImage(":/BoboAndNick.png" )
    self._logo2 = QtGui.QImage(":/logo.png")
    self._logo = self._logo2

    labels = (
      u"\N{GREEK SMALL LETTER PHI}", u"\N{GREEK SMALL LETTER LAMDA}",
      QCA.translate("CoordWidget", "H"),
      QCA.translate("CoordWidget", "E"),
      QCA.translate("CoordWidget", "N"),
      QCA.translate("CoordWidget", "Input File"),
      QCA.translate("CoordWidget", "Output File"))

    if lowerMode == CoordWidget.ModeFile or upperMode == CoordWidget.ModeFile:
      self._fileMode = True
    else:
      self._fileMode = False
    cWidget1 = CoordWidget(xyz, proj=projFrom, ell2Ortho=ell2Ortho,
      name='Upper', comboU='File', labels=labels, initMode=upperMode)
    cWidget1.changedSignal.connect(self.changed)

    cWidget2 = CoordWidget(proj=projTo,
      name='Lower', comboU='File', labels=labels, initMode=lowerMode)
    cWidget2.changedSignal.connect(self.changed)

    cWidget2.setValue(*transform(
      cWidget1.proj(), cWidget2.proj(), *cWidget1.xyz()))
    cWidget2.setEll2Ortho(cWidget1.ell2Ortho())
    self.cWidgets = [cWidget1, cWidget2]

    # The "CONVERT FILE" button
    btn = QtGui.QPushButton(QCA.translate("Convert Button", "Convert File"))
    btn.setToolTip(QCA.translate("Convert Button",
      "Click here to convert input File"))
    bsize = self._logo2.size()
    bsize.scale(100, 90, Qt.KeepAspectRatio)
    btn.setFixedWidth(bsize.width());
    btn.setFixedHeight(bsize.height());
    padx = 5
    pady = 10
    region = QtGui.QRegion(QtCore.QRect(
      btn.x() + padx, btn.y() + pady,
      btn.width() - 2 * padx, btn.height() - 2 * pady), QtGui.QRegion.Ellipse)
    btn.setMask(region)
    btn.setStyleSheet("""
      QPushButton {
        border: 2px solid #8f8f91;
        border-radius: 10px;
        color: white;
        font-weight: bold;
        background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1,
                                       stop: 0 #D1D0E2, stop: 1 #383481);
        min-width: 100px;
      }
      QPushButton:pressed {
        background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1,
                                       stop: 0 #383481, stop: 1 #D1D0E2);
      }

      QPushButton:flat {
        border: none; /* no border for a flat push button */
      }

      QPushButton:default {
       border-color: navy;
      }""")
    btn.clicked.connect(self._onConvertBtn)
    btn.setHidden(True)
    self.convertBtn = btn

    layout = QtGui.QVBoxLayout()
    if pointLabel:
      layout.addWidget(pointLabel, alignment=Qt.AlignJustify)
    layout.addWidget(cWidget1)
    layout.addWidget(self.convertBtn, alignment=Qt.AlignCenter)
    layout.addWidget(cWidget2)
    layout.addStretch(0)
    self.setLayout(layout)

    # Hidden key ;-)
    QtGui.QShortcut(QtGui.QKeySequence("Ctrl+H"), self, self._hiddenKey)

  def resizeEvent(self, evt):
    self.backGround = QtGui.QImage(evt.size(),
      QtGui.QImage.Format_ARGB32_Premultiplied)
    p = QtGui.QPainter(self.backGround)
    p.fillRect(self.backGround.rect(), QtGui.QColor(222, 222, 222))
    scaled = self._logo.scaled(evt.size(), Qt.KeepAspectRatio)
    scaledRect = scaled.rect()
    scaledRect.moveCenter(self.backGround.rect().center())
    p.drawImage(scaledRect, scaled)

    palette = self.palette()
    brush = QtGui.QBrush(self.backGround)
    palette.setBrush(self.backgroundRole(), brush)
    self.setPalette(palette)
    super(CoordDialog, self).resizeEvent(evt)

  def _hiddenKey(self):
    """ Some credits to the authors...
    """
    if self._logo == self._logo1:
      self._logo = self._logo2
    else:
      self._logo = self._logo1
    size = self.size()
    self.resizeEvent(QtGui.QResizeEvent(size, size))

  def _onConvertBtn(self):
    w1 = self.cWidgets[0]
    w2 = self.cWidgets[1]

    if self.cWidgets[0].filePath() and self.cWidgets[1].filePath():
      # Both input and output files defined and valid; convert?
      for c in self.cWidgets:
        if c.filePickerMode() == FilePicker.OutputMode:
          # This is output
          outC = c
        else:
          inC = c
      msgBox = QtGui.QMessageBox(QtGui.QMessageBox.Question,
        QCA.translate("Ok to convert", 'Convert File'),
        QCA.translate("Ok to convert",
          "Ok to convert\n'%s' to\n'%s'\nwith format '%s' ?") %
          (inC.filePath(), outC.filePath(),  outC.coordFormat()),
        QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel)
      if msgBox.exec_() == QtGui.QMessageBox.Ok:
        self.inC = inC
        self.outC = outC
        if inC.filePath() != self._lastInputFilePath:
          self.selectFields(inC.filePath(), inC.isLatLon(), inC.ell2Ortho())
          self._lastInputFilePath = inC.filePath()
        else:
          self._convertFile(self._lastSelection)
      else:
        pass

  def selectFields(self, pn, longLat, ortho=None):
    """ Select fields for file pn

    :param pn: pathname of the file from which select the fields
    :type pn: string, unicode
    :param longLat: True (geographic coordinates) or False (easting, northing)
                         requiredIndexes
    :type longLat: bool
    :param ortho: Orthometric height or None
    :type ortho: float or None
    :raises:
    """
    self.dlg = FieldsWizard(pathName=pn, longLat=longLat, ortho=ortho)
    self.dlg.selectionDoneSignal.connect(self._convertFile)
    self.dlg.exec_()

  def _convertFile(self, d):
    """ Format has been selected, close dialog and convert file
    """
    self._lastSelection = d
    self.dlg.close()
    tic = time.time()

    # Read ASCII file
    names = d['names']
    data = readASCII(d['pathName'], names, d['formats'],
      headerlines=d['headerLines'], removeEmptyLines=True, commentChars='#')

    try:
      x, y, z, isOrtho = self.dlg.data2Degrees(data, names)
    except IndexError:
      # Issue an error message
      mbox = QtGui.QMessageBox()
      mbox.setWindowTitle(QCA.translate("Error message",
        'ERROR reading input file.....'))
      mbox.setIcon(QtGui.QMessageBox.Critical)
      mbox.setInformativeText(QCA.translate("Error message",
        "ERROR!\nCannot understand input file:\n"
        "Maybe format or projection is wrong?"))
      mbox.setStandardButtons(QtGui.QMessageBox.Ok)
      mbox.setDefaultButton(QtGui.QMessageBox.Ok)
      mbox.button(QtGui.QMessageBox.Ok).setText(QCA.translate("Error message",
        'Sorry'))
      ret = mbox.exec_()
      return

    x1, y1, z1, ell2Ortho = self._transform(self.inC, self.outC, (x, y, z))

    if self.outC.heightWidget.rep():
      # Orthometric selected
      z1 += ell2Ortho
      hType = QCA.translate("HeightWidget", "Heights are orthometric")
    else:
      hType = QCA.translate("HeightWidget", "Heights are ellipsoidic")

    xyzDegrees = (x1, y1, z1)

    fmt = ''
    xyz = []
    xdecimals, ydecimals, zdecimals = self.outC.decimals()
    for i, decimals in enumerate((xdecimals, ydecimals)):
      if isinstance(decimals, tuple):
        if i == 0:
          # Number of digits for longitude
          degdigits = 3
        else:
          # Number of digits for latitude
          degdigits = 2

        if len(decimals) == 1:
          # Degrees
          fmt += '%%.%df' % decimals[0]
          xyz.append(xyzDegrees[i])
        elif len(decimals) == 2:
          # Degrees, Minutes.decimals
          fmt += '%%0%d.0f%s%%0%d.%df%s' % (
            degdigits, self._dmsChars[0], 3 + xdecimals[1],
            xdecimals[1], self._dmsChars[1])
          dd, mm = d2dm(xyzDegrees[i], xdecimals[1])
          xyz.append(dd)
          xyz.append(mm)
        elif len(decimals) == 3:
          # Degrees, Minutes, Seconds.decimals
          fmt += '%%0%d.0f%s%%02.0f%s%%0%d.%df%s' % (
            degdigits, self._dmsChars[0], self._dmsChars[1],
            3 + xdecimals[2], xdecimals[2], self._dmsChars[2])
          dd, mm, ss = d2dms(xyzDegrees[i], xdecimals[2])
          xyz.append(dd)
          xyz.append(mm)
          xyz.append(ss)
      else:
        fmt += ' %%.%df' % xdecimals
        xyz.append(xyzDegrees[i])
      fmt += ' '

    fmt += ' %%.%df\n' % zdecimals
    xyz.append(xyzDegrees[2])

    xyz = np.vstack(xyz)

    # Create a header
    header = QCA.translate("outfile", "# Converted on %s:\n") % (time.asctime())
    header += QCA.translate("outfile", "# From Proj.4: '%s' - %s\n") % (
      self.inC.projString(), hType)
    header += QCA.translate("outfile", "#   To Proj.4: '%s' - %s\n") % (
      self.outC.projString(), hType)

    #writeASCII(self.outC.filePath(), xyz, fmt, header)
    tf = ThreadedFunc(writeASCII, self.outC.filePath(), xyz, fmt, header)
    pd = ProgressDialog(tf, title=QCA.translate("ProgressDialog",
      "Conversion in progress..."),
      msg=QCA.translate("ProgressDialog", "Converting..."))

    # Issue a "Done" message
    mbox = QtGui.QMessageBox()
    mbox.setWindowTitle(QCA.translate("Done message", 'File Conversion'))
    mbox.setIcon(QtGui.QMessageBox.Information)
    mbox.setInformativeText(QCA.translate("Done message",
      "File has been convertd to %s\n"
      "Output format is '%s'.") %
      (self.outC.filePath(), self.outC.coordFormat()))
    mbox.setStandardButtons(QtGui.QMessageBox.Ok)
    mbox.setDefaultButton(QtGui.QMessageBox.Ok)
    mbox.button(QtGui.QMessageBox.Ok).setText(
      QCA.translate("Done message", 'Ok'))
    ret = mbox.exec_()

  def fileMode(self):
    """ Return True if widget is in `File` mode

      :returns: widget file mode
      :rtype: bool
    """
    return self._fileMode

  def changed(self, what):
    """ Something changed: either coordinates or Datum / Projection.

        Transform coordinates of the "other" point accordingly

    :param what: argument of the changedSignal emitted by the coordWidget
    :type what: Python Object
    :raises:
    """
    changed = self.sender()
    cWidgets = self.cWidgets[:]
    cWidgets.remove(changed)
    unchanged = cWidgets[0]

    if what == 'point':
      x1, y1, z1, ell2Ortho = self._transform(changed, unchanged, changed)
      # Update widget's value
      unchanged.setValue(x1, y1, z1)
      # No need to change ell2Ortho if we don't change Datum
    elif what == 'proj':
      x1, y1, z1, ell2Ortho = self._transform(unchanged, changed, unchanged)
      # Update widget's value
      changed.setValue(x1, y1, z1)
      changed.setEll2Ortho(ell2Ortho)
      unchanged.setEll2Ortho(ell2Ortho)
      # Clear lastInputFilePath to force input fields selection
      self._lastInputFilePath = None
    elif what == 'File On':
      # Enable File Conversion Mode
      if changed.filePickerMode() == unchanged.filePickerMode():
        #########################
        # THIS HAPPENS ONLY ONCE!
        #########################
        # Both are input: Set to output the unchanged:
        unchanged.setFilePickerMode(FilePicker.OutputMode)
        # Disable "File" selection in unchanged
        unchanged.enableFileMode(False)

      # Show both file pickers
      changed.showFilePicker(True)
      unchanged.showFilePicker(True)
      self._fileMode = True
      self.convertBtn.setHidden(False)
      self.adjustSize()
    elif what == 'File Off':
      if changed.filePickerMode() == FilePicker.InputMode:
        # Hide both file pickers
        changed.showFilePicker(False)
        unchanged.showFilePicker(False)
        self._fileMode = False
        self.convertBtn.setHidden(True)
        self.adjustSize()

  def _transform(self, p0, p1, p):
    """ Transform coordinates of point(s) p from p0 to p1
    """
    if isinstance(p, CoordWidget):
      x, y, z = p.xyz()
    else:
      x, y, z = p
    pointToConvert = x, y, z
    fromProjection = p0.proj()

    if p0.datumShift() or p1.datumShift() or p0.geoidGrid() or p1.geoidGrid():
      # Transform p to p_WGS84
      p84 = Proj(CoordWidget.WGS84)
      x84, y84, z84 = transform(p0.proj(), p84, x, y, z)

    if p1.datumShift() and not p0.datumShift():
      # ONLY p1
      # Get correction for p_WGS84
      lonc, latc = p1.datumShift().getLLCorrection((x84, y84))
      if lonc is None:
        noDatumShift((x84, y84))
        xyzT = (0, 0, 0)
      else:
        if p1.isLatLon():
          unimplemented()
          xyzT = transform(p84, p1.proj(), x - lonc, y - latc) + (z, )
        else:
          xyzT = p1.proj()(x84 + lonc, y84 + latc) + (z, )
    elif p0.datumShift() and not p1.datumShift():
      # ONLY p0
      # Get correction for p_WGS84
      lonc, latc = p0.datumShift().getLLCorrection((x84, y84))
      if lonc is None:
        noDatumShift((x84, y84))
        xyzT = (0, 0, 0)
      else:
        if p0.isLatLon():
          unimplemented()
          xyzT = transform(p84, p1.proj(), x - lonc, y - latc) + (z, )
        else:
          tx, ty = p0.proj()(x, y, inverse=True)
          xyzT = transform(p84, p1.proj(), tx - lonc, ty - latc) + (z, )
    elif p0.datumShift() and p1.datumShift():
      # BOTH!
      # Get correction for p_WGS84
      lon0c, lat0c = p0.datumShift().getLLCorrection((x84, y84))
      lon1c, lat1c = p1.datumShift().getLLCorrection((x84, y84))
      if lon0c is None or lon1c is None:
        noDatumShift((x84, y84))
        xyzT = (0, 0, 0)
      else:
        if p0.isLatLon():
          unimplemented()
          xyzT = (0, 0, 0)
        else:
          tx, ty = p0.proj()(x, y, inverse=True)
          xyzT = p1.proj()(tx - lon0c + lon1c, ty - lat0c + lat1c) + (z, )
    else:
      # No datumShift
      xyzT = transform(p0.proj(), p1.proj(), x, y, z)

    # Geoid Correction
    ell2Ortho = None
    if p0.geoidGrid():
      # Get Geoid Correction
      correction = p0.geoidGrid().getCorrection((x84, y84))
      if correction is not None:
        ell2Ortho = - correction

    if p1.geoidGrid():
      # Get Geoid Correction
      correction = p1.geoidGrid().getCorrection((x84, y84))
      if correction is not None:
        if ell2Ortho is None:
          ell2Ortho = correction
        else:
          ell2Ortho += correction

    return xyzT + (ell2Ortho, )

if __name__ == '__main__':
  import os
  import argparse
  from signal import signal, SIGINT, SIG_DFL

  signal(SIGINT, SIG_DFL)
  app = QtGui.QApplication(sys.argv)

  # i18n for standard widgets
  qTranslator = QtCore.QTranslator()
  ok = qTranslator.load("qt_" + QtCore.QLocale.system().name(),
    QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath))
  if not ok:
    # Workaround for italian
    ok = qTranslator.load("qt_" + QtCore.QLocale.system().name())
  app.installTranslator(qTranslator)

  # i18n for our application
  translator = QtCore.QTranslator()
  ok = translator.load("i18n_" +  QtCore.QLocale.system().name())
  app.installTranslator(translator)

  #moloSartorioWGS84 = (((13., 45., 34.397), (45., 38., 49.879), 52.8),
  moloSartorioWGS84 = (((13.763647000), (45.710551000), 285.800),
    '+proj=latlong +datum=WGS84',
    '+init=epsg:3004 +towgs84=-122.74,-34.27,-22.83,'
    '-1.884,-3.400,-3.030,-15.62',
    None, 'Molo Sartorio')

  moloSartorioUTM33 = (((403768.542,), (5062631.809,), 285.8),
    '+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +no_defs',
    '+proj=longlat +ellps=intl +pm=rome +no_defs',
    None, 'Molo Sartorio')

  parser = argparse.ArgumentParser(prog=os.path.basename(sys.argv[0]))
  parser.add_argument('-p', '--point', default="(0, 0, 0)",
    help=QCA.translate('main', 'point coordinates '
    "(default: '%(default)s')"))
  parser.add_argument('-u', '--upperProj', default=CoordWidget.WGS84,
    help=QCA.translate('main', 'upper Proj.4 string '
    "(default: '%(default)s')"))
  parser.add_argument('-l', '--lowerProj', default=CoordWidget.WGS84,
    help=QCA.translate('main', 'lower Proj.4 string '
    "(default: '%(default)s')"))
  parser.add_argument('-e', '--ell2Ortho', default='None',
    help=QCA.translate('main',
    'optional height to add to get orthometric height '
    "(default: '%(default)s')"))
  parser.add_argument('-n', '--name', default='',
    help=QCA.translate('main',
    'optional name for the dialog '
    "(default: '%(default)s')"))
  parser.add_argument('-U', '--upperMode', default=str(CoordWidget.ModeD),
    help=QCA.translate('main',
    'optional upper widget representation [0..2] '
    "(default: '%(default)s')"))
  parser.add_argument('-L', '--lowerMode', default=str(CoordWidget.ModeDMS),
    help=QCA.translate('main',
    'optional lower widget representation [0..2] '
    "(default: '%(default)s')"))
  parser.add_argument('-d', '--dmsChars', default=u"""["°", "'", '"']""",
    help=QCA.translate('main', 'degrees, minutes, seconds characters '
    "(default: '%(default)s')"))
  o = parser.parse_args(sys.argv[1:])

  #dialog = CoordDialog(*moloSartorioUTM33)
  #dialog = CoordDialog(*moloSartorioWGS84)
  dialog = CoordDialog(eval(o.point), o.upperProj, o.lowerProj,
    eval(o.ell2Ortho), o.name, eval(o.upperMode), eval(o.lowerMode),
    eval(o.dmsChars))
  dialog.show()
  app.exec_()

